﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Intorise.Common;
using System.Threading;
using Intorise.Net;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
using Microsoft.Office.Interop.Excel;
using System.Reflection;
using System.Xml.Serialization;
using Model;
using TestWindowsFormsApplication.Validator;
using TestWindowsFormsApplication.Analyzer;

namespace TestWindowsFormsApplication
{
    public partial class Lu : Form
    {
        static string ORDER_NAME = "跟踪单号";
        static string ORDER_NAME1 = "物流单号";
        static string STATUS_NAME = "妥投状态";
        static string INFO_NAME = "妥投状态备注";
        static string URL_NAME = "物流网址";
        static int RETRY_COUNT = 2;
        bool completed = false;

        #region post url
        readonly string TRACK_URL = "http://www.17track.net/r/handlertrack.ashx?callback=a&num={0}&pt=0&cm=0&cc=0&_={1}";//17track查询请求url
        readonly string DHL_URL = "http://www.cn.dhl.com/shipmentTracking?AWB={0}&countryCode=cn&languageCode=zh&_={1}";//dhl查询请求url
        readonly string DHL_URL_0 = "http://www.cn.dhl.com/shipmentTracking?countryCode=cn&fromDayValue={3}&fromMonthValue={2}&fromYearValue={1}&languageCode=zh&shipperReference={0}&toDayValue={6}&toMonthValue={5}&toYearValue={4}&_={7}";//dhl转单查询
        readonly string UPS_URL = "http://www.17track.net/r/handlertrack.ashx?callback=a&num={0}&et=100002&_={1}";//ups查询请求url
        readonly string TNT_URL = "http://www.17track.net/r/handlertrack.ashx?callback=a&num={0}&et=100004&_={1}";//tnt查询请求url
        readonly string DPD_URL = "http://www.17track.net/r/handlertrack.ashx?callback=a&num={0}&et=100010&_={1}";//dpd查询请求url
        readonly string SF_URL = "http://www.sf-express.com/sf-service-web/service/bills/{0}/routes?app=bill&lang=sc&region=cn&translate=";//顺风
        readonly string ARA_URL = "http://www.17track.net/r/handlertrack.ashx?callback=a&num={0}&et=100006&_={1}";//aramex查询请求url
        readonly string EC_URL = "http://www.ec-firstclass.org/Details.aspx";
        readonly string PX_URL = "http://4px.com/";
        readonly string RPX_URL = "http://www.rpxonline.com/index.php?option=com_track&view=tracking";
        readonly string FEDEX_URL = "https://www.fedex.com/trackingCal/track?action=trackpackages&locale=zh_CN&version=1&format=json&data={%22TrackPackagesRequest%22:{%22appType%22:%22WTRK%22,%22uniqueKey%22:%22%22,%22processingParameters%22:{},%22trackingInfoList%22:[{%22trackNumberInfo%22:{%22trackingNumber%22:%22<ORDERNO>%22,%22trackingQualifier%22:%22%22,%22trackingCarrier%22:%22%22}}]}}&_=";
        readonly string AUSPOST_URL = "http://auspost.com.au/track/track.html?exp=b";
        #endregion

        #region Regex
        Regex ausLocationRegex = new Regex(@"<div class=""cell-float-right ed-location"">\s+<p>(.*)</p>\s+</div>");
        Regex ausSubmitDateRegex = new Regex(@"<div class=""cell-float-left ed-date"">\s+<p>\s+(.*)\s+</p>\s+</div>");
        Regex regex_p = new Regex("<p>.*</p>");
        #endregion

        List<DataInfo> datas = new List<DataInfo>();
        NetTools tools = new NetTools(30);
        bool processing = false;
        DateTime beginTime = DateTime.Now;
        WebClient client = new WebClient();

        public Lu()
        {
            InitializeComponent();
            Form.CheckForIllegalCrossThreadCalls = false;
            if (DateTime.Now.Hour < 6)
            {
                ShowStatus("凌晨了还不休息！");
            }
            else if (DateTime.Now.Hour < 12)
            {
                ShowStatus("早上好，宝贝，记得吃早餐！");
            }
            else if (DateTime.Now.Hour < 18)
            {
                ShowStatus("中午好，宝贝，休息会吧！");
            }
            else
            {
                ShowStatus("晚上好，早点休息哦！");
            }

            Program.MainForm = this;
        }

        private void 加载ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var result = this.ofd.ShowDialog();
            if (result == DialogResult.OK)
            {
                datas.Clear();
                List<string> errorFiles = new List<string>();
                foreach (string f in ofd.FileNames)
                {
                    try
                    {
                        DataInfo info = new DataInfo();
                        info.ExceFile = new FileInfo(f);
                        info.Table = OfficeTools.GetDataTableFromExcel(f, "划款审单下载$");

                        for (int i = 0; i < info.Table.Columns.Count; i++)
                        {
                            if (info.Table.Rows[0][i].ToString() != "")
                            {
                                info.Table.Columns[i].ColumnName = info.Table.Rows[0][i].ToString();
                            }
                        }
                        info.Table.Rows.RemoveAt(0);

                        switch (info.Table.TableName)
                        {
                            case "[日审数据下载$]":
                                var column0 = new DataColumn("妥投状态", typeof(string));
                                info.Table.Columns.Add(column0);
                                column0.SetOrdinal(15);
                                column0 = new DataColumn("妥投状态备注", typeof(string));
                                info.Table.Columns.Add(column0);
                                column0.SetOrdinal(16);
                                info.Type = 0;
                                break;
                            case "[划款审单下载$]":
                                var column = new DataColumn("妥投状态", typeof(string));
                                info.Table.Columns.Add(column);
                                column.SetOrdinal(13);
                                column = new DataColumn("妥投状态备注", typeof(string));
                                info.Table.Columns.Add(column);
                                column.SetOrdinal(14);
                                info.Type = 0;
                                break;
                            case "[妥投信息下载$]":
                                info.Type = 1;
                                if (!info.Table.Columns.Contains("妥投状态"))
                                {
                                    var column1 = new DataColumn("妥投状态", typeof(string));
                                    info.Table.Columns.Add(column1);
                                    column1.SetOrdinal(13);
                                }
                                if (!info.Table.Columns.Contains("妥投状态备注"))
                                {
                                    var column2 = new DataColumn("妥投状态备注", typeof(string));
                                    info.Table.Columns.Add(column2);
                                    column2.SetOrdinal(14);
                                }
                                break;
                        }

                        info.QueryResult = new List<FreightInfo>(info.Table.Rows.Count);
                        datas.Add(info);
                    }
                    catch (Exception ex)
                    {
                        errorFiles.Add(f); MessageBox.Show(ex.Message);
                    }
                }

                if (errorFiles.Count > 0)
                {
                    MessageBox.Show("以下文件没有加载成功，可能格式有误，请联系开发者！\r\n" + string.Join("\r\n", errorFiles));
                }
                ShowMessageLine(string.Format("成功加载了{0}个文件！", datas.Count));
            }
        }

        private void 开始ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.datas.Count == 0)
            {
                MessageBox.Show("请先加载电子表格文件！"); return;
            }
            completed = false;
            this.processing = true;
            this.加载ToolStripMenuItem.Enabled = false;
            this.开始ToolStripMenuItem.Enabled = false;
            this.btnLoad.Enabled = false;
            this.btnProcess.Enabled = false;
            this.btnConfig.Enabled = false;
            Thread thread = new Thread(new ParameterizedThreadStart(process));
            thread.Start();
            beginTime = DateTime.Now;
            ShowStatus("正在处理，请稍候！");
        }

        private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void Lu_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (processing && MessageBox.Show("正在处理数据，是否确定要退出？", "警告", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
            {
                e.Cancel = true;
            }
        }

        private void process(object obj)
        {
            //Thread thread = new Thread(new ParameterizedThreadStart(x =>
            //{
            //    while (!completed)
            //    {
            //        var pointer = Intorise.API.Windows.FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, "安全警报");
            //        if (pointer != IntPtr.Zero)
            //        {
            //            Intorise.API.Helper.SendKeyPress(pointer, Keys.Enter);
            //        }
            //        pointer = Intorise.API.Windows.FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, "脚本错误");
            //        if (pointer != IntPtr.Zero)
            //        {
            //            Intorise.API.Helper.SendKeyPress(pointer, Keys.Enter);
            //        }
            //        Thread.Sleep(500);
            //    }
            //    ConsoleBLL.WriteLine("关闭安全警报完成");
            //}));
            //thread.Start();

            this.progress.Minimum = 0;
            this.progress.Maximum = this.datas.Sum(x => x.Table.Rows.Count);

            datas.ForEach(x =>
            {
                if (!x.ExceFile.Exists) { ShowMessageLine(string.Format("文件{0}不存在，跳过了", x.ExceFile.FullName)); return; }
                int index = 0;
                ShowMessageLine(string.Format("开始处理文件{0}...", x.ExceFile.FullName));
                string orderName = x.Type == 0 ? ORDER_NAME : ORDER_NAME1;

                List<DataRow> tracks = new List<DataRow>();
                foreach (DataRow row in x.Table.Rows)
                {
                    int retryCount = 0;
                    this.progress.Value++;
                    index++;
                Start:
                    ShowStatus(string.Format("正在处理{0}/{1}...", this.progress.Value, this.progress.Maximum));
                    string orderNo = null;
                    try
                    {
                        if (row[0] is DBNull || row[0].ToString() == "" || row[0].ToString() == "商户号")
                        {
                            continue;
                        }
                        orderNo = row[orderName].ToString().Trim().ToUpper();
                        string url = row[URL_NAME].ToString();
                        FreightInfo info = null;
                        //if (FreightInfoAnalyzer.Is17Track(url, orderNo))
                        //{
                        //    tracks.Add(row);
                        //}
                        //else
                        {
                            info = FreightInfoAnalyzer.Analyse(url, orderNo);
                            switch (info.Status)
                            {
                                case "重试":
                                    if (retryCount < RETRY_COUNT)
                                    {
                                        ShowMessageLine(string.Format("出现错误，单号{2}，重试...", x.ExceFile.FullName, index, orderNo));
                                        retryCount++;
                                        Thread.Sleep(3 * 1000);
                                        goto Start;
                                    }
                                    break;
                                case "需要输入验证码":
                                    DialogResult result = new ValidateCodeFrom().ShowValidateCode();
                                    if (result != DialogResult.OK)
                                    {
                                        ShowMessageLine("出现验证码等待30秒后重试...");
                                        Refresh17track("RC386198748HK");
                                        Thread.Sleep(30 * 1000);
                                    }

                                    if (retryCount < RETRY_COUNT)
                                    {
                                        retryCount++;
                                        goto Start;
                                    }
                                    break;
                                case "查询过于频繁":
                                    ShowMessageLine("查询过于频繁，等待180秒后重试...");
                                    Refresh17track("RC386198748HK");
                                    Thread.Sleep(180 * 1000);
                                    if (retryCount < RETRY_COUNT)
                                    {
                                        retryCount++;
                                        goto Start;
                                    }
                                    break;
                            }

                            x.QueryResult.Add(info);
                            row[STATUS_NAME] = info.Status;
                            //row[STATUS_INDEX] = info.Status == "y" ? "已妥投" : "未妥投";
                            row[INFO_NAME] = info.ResultText;
                            if (info.ShipDate.HasValue)
                            {
                                row[INFO_NAME] += "," + info.ShipDate.Value.ToShortDateString();
                            }
                            Thread.Sleep(5000);
                        }
                    }
                    catch (Exception ex)
                    {
                        #region
                        if (retryCount < RETRY_COUNT)
                        {
                            retryCount++;
                            ShowMessageLine(string.Format("处理{0}的第{1}行数据时出现错误，单号{2}，重试...", x.ExceFile.FullName, index, orderNo));
                            ShowMessageLine(ex.Message);
                            goto Start;
                        }
                        else
                        {
                            ShowMessageLine(string.Format("处理{0}的第{1}行数据时出现错误，单号{2}的数据被跳过。", x.ExceFile.FullName, index, orderNo));
                            ShowMessageLine(ex.Message);
                            row[STATUS_NAME] = "出错跳过";
                        }
                        #endregion
                    }
                }//end foreach



                try
                {
                    var dir = Directory.CreateDirectory(x.ExceFile.Directory + "\\已处理");
                    var templeteFile = "";
                    if (x.Table.TableName == "[划款审单下载$]")
                    {
                        templeteFile = "templete.xls";
                    }
                    else if (x.Table.TableName == "[日审数据下载$]")
                    {
                        templeteFile = "templete1.xls";
                    }
                    else
                    {
                        templeteFile = "templete0.xls";
                    }
                    OfficeTools.TableToExcelFile(x.Table, dir.FullName + "\\已处理_" + x.ExceFile.Name, AppDomain.CurrentDomain.BaseDirectory + "\\" + templeteFile);
                    ShowMessageLine(string.Format("文件{0}以保存。", x.ExceFile.FullName));
                    if (chkAnalysis.Checked)
                    {
                        ProcessColor(x, dir);
                    }
                }
                catch (Exception ex)
                {
                    ShowMessageLine(string.Format("保存文件{0}时出现错误：", x.ExceFile.FullName));
                    ShowMessageLine(ex.Message); ShowMessageLine(ex.StackTrace);
                }

                Thread.Sleep(3000);
            });
            completed = true;
            var time = DateTime.Now - beginTime;
            ShowMessageLine(string.Format("全部加载的{0}个文件约{1}条数据已经处理完成，用时：{2}，速度：{3}个/小时！",
                datas.Count, this.progress.Maximum, time.ToString(), Math.Round(this.progress.Maximum / time.TotalHours)));
            ShowStatus("处理完成！");

            this.加载ToolStripMenuItem.Enabled = true;
            this.开始ToolStripMenuItem.Enabled = true;
            this.btnLoad.Enabled = true;
            this.btnProcess.Enabled = true;
            this.btnConfig.Enabled = true;
            this.processing = false;
            this.progress.Value = 0;
        }

        private void ShowMessage(string text)
        {
            this.richTextBox1.AppendText(text);
        }
        public void ShowMessageLine(string text)
        {
            this.richTextBox1.AppendText(text + "\r\n");
        }
        private void ShowStatus(string text, bool appendMessage = false)
        {
            this.toolStripStatusLabel1.Text = text;
            if (appendMessage)
            {
                ShowMessageLine(text);
            }
        }

        private void Lu_SizeChanged(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)  //判断是否最小化
            {
                this.ShowInTaskbar = false;  //不显示在系统任务栏
                notifyIcon1.Visible = true;  //托盘图标可见
            }
        }

        private void notifyIcon1_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Normal;
            this.BringToFront();
        }



        private void ProcessColor(DataInfo dataInfo, DirectoryInfo dir)
        {
            string excelFilename = dataInfo.ExceFile.Directory + "\\已处理\\已处理_" + dataInfo.ExceFile.Name;
            Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
            Workbooks wbks = app.Workbooks;
            _Workbook _wbk = wbks.Add(excelFilename);
            Sheets shs = _wbk.Sheets;
            _Worksheet _wsh = (_Worksheet)shs.get_Item(1);
            //((Range)_wsh.Rows[1, Missing.Value]).Interior.ColorIndex = 3;

            DateTime time;
            var statusIndex = dataInfo.Table.Columns[STATUS_NAME].Ordinal;
            var infoIndex = dataInfo.Table.Columns[INFO_NAME].Ordinal;
            for (int i = 0; i < dataInfo.Table.Rows.Count; i++)
            {
                //string resultText = dataInfo.Table.Rows[i][INFO_INDEX].ToString().ToLower();
                if (((Range)_wsh.Cells[i + 3, statusIndex + 1]).Value == "n")
                {
                    continue;
                }
                var value = ((Range)_wsh.Cells[i + 3, infoIndex + 1]).Value;
                if (value == null) { continue; }
                string resultText = value.ToString().ToLower();

                if (DateTime.TryParse(dataInfo.Table.Rows[i]["交易时间"].ToString(), out time) && dataInfo.QueryResult[i].ShipDate.HasValue)
                {
                    if (time > dataInfo.QueryResult[i].ShipDate.Value)
                    {
                        ((Range)_wsh.Cells[i + 3, infoIndex + 1]).Interior.ColorIndex = EXcelColorIndex.红色;//红色
                    }
                }
                string zip = dataInfo.Table.Rows[i]["邮编"].ToString().ToLower();

                #region 发往法国邮编正确就是正确的否则即错误
                if (dataInfo.QueryResult[i].ResultText.Contains("distribué"))//发往法国邮编正确
                {
                    var zip0 = Tools.SubString(dataInfo.QueryResult[i].ResultText, "(", ")", true);
                    if (string.IsNullOrEmpty(zip0) || !zip.StartsWith(zip0))
                    {
                        ((Range)_wsh.Cells[i + 3, infoIndex + 1]).Interior.ColorIndex = EXcelColorIndex.红色;//红色
                    }
                    continue;
                }
                #endregion

                string countryCode = dataInfo.Table.Rows[i]["IP所在国家"].ToString();
                string city = dataInfo.Table.Rows[i]["城市"].ToString().ToLower();
                string state = dataInfo.Table.Rows[i]["州"].ToString().ToLower();
                var country = LuluHelper.GetCountry(countryCode);

                IValidate validator = null;
                switch (dataInfo.QueryResult[i].OrderType)
                {
                    case OrderTypeEnum.DHL:
                        validator = new DhlValidator();
                        break;
                    default:
                        validator = new NormalValidator();
                        break;
                }

                var result = validator.Validate(country, zip, state, city, dataInfo.Table.Rows[i], dataInfo.QueryResult[i]);
                switch (result)
                {
                    case ValidateResutlEnum.Incorrect:
                        ((Range)_wsh.Cells[i + 3, infoIndex + 1]).Interior.ColorIndex = EXcelColorIndex.红色;
                        break;
                    case ValidateResutlEnum.Indeterminacy:
                        ((Range)_wsh.Cells[i + 3, infoIndex + 1]).Interior.ColorIndex = EXcelColorIndex.橙色;
                        break;
                    default:
                        break;
                }
            }

            app.AlertBeforeOverwriting = false;
            _wbk.SaveAs(dataInfo.ExceFile.Directory + "\\已处理\\已分析_" + dataInfo.ExceFile.Name, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
            _wbk.Close(null, null, null);
            wbks.Close();
            app.Quit();
            //File.Delete(excelFilename);
            //释放掉多余的excel进程
            System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
            app = null;
        }

        private void Refresh17track(string order)
        {
            this.webBrowser1.Navigate("about:blank");
            this.webBrowser1.Navigate("http://www.17track.net/zh-cn/track?nums=" + order + "&fc=0");
            ShowMessageLine("无法查询数据，刷新网站！");
        }

        private void ProcessMutl(List<DataRow> tracks, string orderName, DataInfo x)
        {
            if (tracks.Count > 0)
            {
                List<FreightInfo> results = new List<FreightInfo>();
                EmsAnalyzer analyzer = new EmsAnalyzer();
                analyzer.RefreshAction = this.Refresh17track;
                analyzer.ShowMessageAction = this.ShowMessageLine;

                int count = tracks.Count / 39;
                if (tracks.Count % 39 > 0)
                {
                    count++;
                }
                for (var i = 0; i < count; i++)
                {

                    var rows = tracks.Skip(i * 39).Take(39).ToList();
                    ShowMessageLine("开始处理第" + (i + 1) + "批" + rows.Count + "个单号...");
                    var infos = analyzer.Analyse(rows.Select((a) => a[orderName].ToString().Trim().ToUpper()).ToList());
                    if (infos.Count == 0)
                    {
                        Thread.Sleep(5000);
                        results.AddRange(analyzer.Analyse(rows.Select((a) => a[orderName].ToString().Trim().ToUpper()).ToList()));
                    }
                    else
                    {
                        results.AddRange(infos);
                    }
                    if (i < count - 1)
                    {
                        Thread.Sleep(rows.Count * 2);
                    }
                }


                results.ForEach(f =>
                {
                    var rows = x.Table.Select(x.Table.Columns[orderName].ColumnName + "='" + f.OrderNO + "'");
                    if (rows.Length == 0)
                    {
                        return;
                    }
                    rows[0][STATUS_NAME] = f.Status;
                    //row[STATUS_INDEX] = info.Status == "y" ? "已妥投" : "未妥投";
                    rows[0][INFO_NAME] = f.ResultText;
                    if (f.ShipDate.HasValue)
                    {
                        rows[0][INFO_NAME] += "," + f.ShipDate.Value.ToShortDateString();
                    }
                });
            }
        }
    }
}
